package com.chengqs.summer.utils;

import com.chengqs.summer.io.InputStreamCallback;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;

/**
 * 工具类，用于从类路径中读取资源文件。
 *
 * 本类提供了从类路径中读取文件的功能，并允许通过回调机制处理输入流。它应用了以下设计模式：
 *
 * <h2>1. 回调模式（Callback Pattern）(行为)</h2>
 * <p>
 * 回调模式通过 `InputStreamCallback<T>` 接口实现，使得 `readInputStream` 方法可以接收用户自定义的处理逻辑。
 * 这允许用户在不修改 `ClassPathUtils` 类本身的情况下，定义如何处理读取到的输入流。例如，`readString`
 * 方法使用了回调机制，将输入流的数据读取为字符串。回调模式提供了灵活性，使得同一个读取方法可以
 * 适用于不同的处理需求。
 * </p>
 *
 * <h2>2. 工厂模式（Factory Pattern）(创建)</h2>
 * <p>
 * 工厂模式在 `getContextClassLoader` 方法中体现，通过封装类加载器的获取逻辑，简化了资源访问的过程。
 * `getContextClassLoader` 方法负责提供一个 `ClassLoader` 实例，用于从类路径中读取资源。用户无需关心
 * 类加载器的具体实现细节，只需调用类中的方法即可。这种设计将资源访问与类加载器的具体实现解耦，
 * 提高了代码的灵活性和可维护性。
 * </p>
 *
 * <h2>功能概述</h2>
 * <p>
 * - `readInputStream(String path, InputStreamCallback<T> inputStreamCallback)` 方法用于从类路径中读取指定路径的资源，
 *   并通过回调接口处理输入流。
 * - `readString(String path)` 方法利用回调模式，将读取到的输入流内容转换为字符串。
 * - `getContextClassLoader()` 方法用于获取类加载器实例，支持从类路径中读取资源。
 * </p>
 */
public class ClassPathUtils {

    /**
     * 从类路径中读取指定路径的资源，并使用回调处理输入流。
     * @param path 资源文件在类路径中的路径。
     * @param inputStreamCallback 回调接口，用于处理读取到的输入流。
     * @return 回调方法 doWithInputStream 的返回值。
     * @param <T> 回调方法 doWithInputStream 的返回值类型。
     */
    public static <T> T readInputStream(String path, InputStreamCallback<T> inputStreamCallback) {
        if (path.startsWith("/")) {
            // 如果路径以斜杠 / 开头，则将其去掉，以适应类路径中的资源定位。
            path = path.substring(1);
        }
        // 通过 getContextClassLoader().getResourceAsStream(path) 从类路径中获取资源的输入流。
        try (InputStream input = getContextClassLoader().getResourceAsStream(path)) {
            if (input == null) {
                throw new FileNotFoundException("File not found in classpath: " + path);
            }
            // 通过 InputStreamCallback 接口的 doWithInputStream 方法处理输入流，这种设计提高了代码的灵活性和可重用性。
            return inputStreamCallback.doWithInputStream(input);
        } catch (IOException e) {
            e.printStackTrace();
            throw new UncheckedIOException(e);
        }
    }

    /**
     * 从类路径中读取资源文件，并将其内容作为字符串返回。
     * @param path 资源文件在类路径中的路径。
     * @return 读取到的资源内容的字符串表示。
     */
    public static String readString(String path) {
        return readInputStream(path, (input) -> {
            // 使用 lambda 表达式作为回调，实现了将输入流的字节数据读取到 byte[] 中
            byte[] data = input.readAllBytes();
            // 转换为 String，使用 UTF-8 编码来解码字节数据，确保正确处理文本内容。
            return new String(data, StandardCharsets.UTF_8);
        });
    }

    /**
     * 获取当前线程的上下文类加载器，如果上下文类加载器为 null，则获取 ClassPathUtils 类的类加载器。
     * @return 返回合适的 ClassLoader 实例。
     */
    static ClassLoader getContextClassLoader() {
        ClassLoader cl = null;
        // 优先使用当前线程的上下文类加载器，这通常是应用程序的类加载器。
        cl = Thread.currentThread().getContextClassLoader();
        if (cl == null) {
            // 如果上下文类加载器为 null，则使用 ClassPathUtils 类的类加载器作为备用。
            cl = ClassPathUtils.class.getClassLoader();
        }
        return cl;
    }
}
